LIBRARY ieee;
USE ieee.std_logic_1164.all;
                                                  --引入库和程序包，以此使用std_logic等数据类型

																  
																  
--std_logic_vector标准逻辑向量“1010” 读写顺序从左向右从高位到低位																  
--std_logic 标准逻辑‘0’，‘1’（“” ‘’ 固定语法，整数不加，字符‘’，字符串“”）																  
--STD标准逻辑取值‘0’‘1’‘X’（不定，赋值）‘U’（不定，初始）‘Z’（高阻）‘W’（弱信号不定）‘L’（弱信号0）‘H’（弱信号1）‘-’（不可能情况）														  

																  
--*****************实体部分*************************--
ENTITY Car_tracking IS                             --实体固定语法，‘Car_tracking’作为实体名，同时文件名要与其一致,该文件作为顶层文件则顶层文件名也与其一致
                                                  --GENERIC 是用于说明设计实体和其外部环境通信的对象，规定端口的大小、实体中子元件的数目、实体的延时特性
	GENERIC (												  --此处为实体说明部分
	
--时钟为50MHz，为了产生100Hz的PWM波，设置计数值为500000（相关计算：50*10^6  /100 =500000)

	cnt_meta : INTEGER := 500000;    --计数预设值	500000
	 
--对应了停止、前进、左转、右转状态IN4到IN1的输出（in_motor的逻辑向量输出值预设）

	StopCar : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0000" ;  --（四口低电平）
   Forward : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0110" ;  --（同向正转）--（***）
	Left_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0110" ; 
	Right_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0110"   
	);
	
	
--*********转向的实现方法*********--

--1：Left_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1000"	 Right_Go : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0001" （通过一个轮子转动一个轮子停止实现）
--2：Left_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1001" Right_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1001" （通过在前进的基础上，改变左右轮的转速实现）
--3：Left_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1010" Right_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0101"	 （通过两个轮子，一个正转一个反转实现）



--******************输入输出端口**********************--
                                                      --端口 为信号类signal可省略
PORT (
	signal avoid : IN STD_LOGIC_VECTOR(0 TO 1);      --障碍物信号

	signal sys_clk : IN STD_LOGIC;                     --时钟信号（信号来源为确定的PIN_17产生） 
	signal sys_rst_n : IN STD_LOGIC;		               --复位信号	（信号来源为确定的PIN_90产生）		     
	signal infrared : IN STD_LOGIC_VECTOR(1 DOWNTO 0); --红外信号（1左0右）左右      循迹模块 亮低电平无检测黑线，检测到黑线不亮高电平
	signal en_left : OUT STD_LOGIC;						   --左轮使能（通过EN口‘10’实现）（作为PWM的输出接口）
	signal en_right : OUT STD_LOGIC;					      --右轮使能（通过EN口‘10’实现）（作为PWM的输出接口）
	signal in_motor : OUT STD_LOGIC_VECTOR(3 DOWNTO 0) --电机的四线接口（实际上也可以对电机的四个接口分别使用STD_LOGIC定义，优化代码，一线四口）
	);
  
  END Car_tracking;
--实体部分定义结束--

  
--*******************结构体部分**********************--
                                                             --多个结构体时才需要使用configuration配置结构体间相关关系
ARCHITECTURE trans OF Car_tracking IS                         --architecture 结构名 of 实体名 is
                                                             --结构体说明部分，声明信号（定义语句用于对结构体内部所使用的信号、常数、数据类型和函数等进行定义。）
	SIGNAL cnt : INTEGER;                                     --integer为整数类型，数据输入时直接输入整数即可
	SIGNAL duty_left : INTEGER;
	SIGNAL duty_right : INTEGER;
                                                              --若未被声明则初次声明赋值语法为：signal duty_left ：integer ：= 1；（赋初值时）	
	
BEGIN 
--结构体内P1，P2，P3，同时运行，process内顺序执行

--************循迹程序************--		
	P1: PROCESS (sys_rst_n, infrared)  --接入的信号                   --并行v 语句 [进程名]:PROCESS(信号 1,信号 2,…)
												
	BEGIN

	IF (sys_rst_n = '0') THEN  --当按下复位键后开始执行语句（下降沿复位，由原理图得出）
			duty_right <= 0 ;                                               --信号赋值语法使用 ***<=*** 
			duty_left <= 0;
	ELSE
	
		IF (avoid = "11") THEN  --如果没有检测到障碍物则执行循迹
	
		CASE infrared IS    --红外接口输入的逻辑向量值的情况（左右）           --case语句固定格式，***=>***
		
			WHEN "00" =>  				  --当左右均无黑线时
				in_motor <= StopCar;   --将停止的信号链传递给电机
			
			WHEN "01" =>				  --左无，右有，执行右转
				in_motor <= Right_Go;
					duty_left <= 40;       --PWM占空比（取值0--100）（数值越大，转速越高）
					duty_right <= 60;
		
			WHEN "10" =>				  --左有，右无，执行左转
				in_motor <= Left_Go;
					duty_left <= 60;
					duty_right <= 40;
		
			WHEN OTHERS =>				  --左右均有黑线时，执行前进               --when others作为case中的基础语句
				in_motor <= Forward;
					duty_left <= 60;
					duty_right <= 60;
					
				END CASE;
					
				ELSE  in_motor <= StopCar;  --检测到障碍物则停止
				
			END IF;	
	   END IF;
			
	END PROCESS P1 ;


--***************计数器***************--	
	P2: PROCESS (sys_clk, sys_rst_n)  --接入信号

	BEGIN
	
	IF (sys_rst_n = '0') THEN    --当复位键按下后
			cnt <= 0;				  --为‘计数’赋值整数0
	
	
		ELSIF (sys_clk'EVENT AND sys_clk = '1') THEN   --当clk信号遭遇上升沿则...（开始计数）
--   event事件 即 信号是否发生跳变   跳变后信号变为高电平
--			（发生返回ture，反之假）
		
		
			IF (cnt = cnt_meta) THEN  --判断‘计数’值是否与预设计数次数相同
				cnt <= 0;				  --相同则赋值0，重新开始计数
			ELSE
				cnt <= cnt + 1;		  --不相同则‘计数’值+1
				
			END IF;
		END IF;
		
	END PROCESS P2 ;

--**************PWM功能实现*************--	
	P3: PROCESS (sys_clk, sys_rst_n)  --接入信号
	
	BEGIN
	
	  IF (sys_rst_n = '0') THEN  --如果复位键按下
				en_left <= '0';     --按动复位键时，强制停止
				en_right <= '0';    --（此初值可以任意，当开始运行循迹程序后，会自动赋予相应的值）
				
--左轮PWM		
		ELSIF (sys_clk'EVENT AND sys_clk = '1') THEN  --当clk信号的上升沿则...（开始计数）
	
	
		IF (cnt >= (cnt_meta / 100) * duty_left) THEN --当‘计数’值 大于等于 预设PWM占空数时（公式只为优化代码输入时值位于0-100）
				en_left <= '0';
		ELSE
				en_left <= '1';  
		END IF;
		
--即在计数器（0—0.5M）计数大周期内，在cnt（0——预设pwm占空数）的时间内高电平，在cnt大于预设值时低电平	，以此实现PWM脉宽调制
	
--右轮PWM	
		IF (cnt >= (cnt_meta / 100) * duty_right) THEN	--当‘计数’值 大于等于 预设PWM占空数时（公式只为优化代码输入时值位于0-100）
				en_right <= '0';
		ELSE
				en_right <= '1';
				
					END IF;
				END IF;
		END PROCESS P3 ;

		END trans;
--********结构体定义结束**********--
